package ru.compft.common.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * User: ASUS
 * Date: 02.11.12
 * Time: 9:40
 */
@Aspect
@Component
public class SomeAspect {
    private final ThreadLocal uniqueKey = new ThreadLocal();

    @Pointcut("execution(* ru.compft.common.aop.SomeTestService.executeOperation*(..))")
    public void serviceOperation() {
    }

    @Pointcut("execution(* ru.compft.common.aop.SomeTestService.executeAction*(..))")
    public void serviceAction() {
    }

    @Before(value = "serviceOperation()")
    public void doBusinessOperationBefore() {
        uniqueKey.set(System.nanoTime());
        System.out.println("Before {"+Thread.currentThread().getName()+"}= " + uniqueKey.get());
    }

    @Around("serviceOperation()")
    public Object doBusinessOperationProfiling(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Profiling start {"+Thread.currentThread().getName()+"}= " + uniqueKey.get());
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        System.out.println("Profiling stop {"+Thread.currentThread().getName()+"} = " + uniqueKey.get());
        uniqueKey.set(null);
        return retVal;
    }

    @AfterReturning(pointcut = "serviceOperation()",
            returning = "retVal")
    public void doBusinessOperationAfterReturning(Object retVal) {
        System.out.println("AfterReturning {"+Thread.currentThread().getName()+"}= " + uniqueKey.get());
        uniqueKey.set(null);
    }

    @AfterThrowing("serviceOperation()")
    public void doBusinessOperationAfterThrowing() {
        System.out.println("AfterThrowing {"+Thread.currentThread().getName()+"}= " + uniqueKey.get());
        uniqueKey.set(null);
    }

    // -----------------------------------------------
    @Before(value = "serviceAction()")
    public void doBusinessActionBefore() {
        System.out.println("doBusinessActionBefore = " + uniqueKey.get());
    }

    @Around("serviceAction()")
    public Object doBusinessActionProfiling(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("doBusinessActionProfiling start = " + uniqueKey.get());
        // start stopwatch
        Object retVal = pjp.proceed();
        // stop stopwatch
        System.out.println("doBusinessActionProfiling stop = " + uniqueKey.get());
        return retVal;
    }

    @AfterReturning(pointcut = "serviceAction()",
            returning = "retVal")
    public void doBusinessActionAfterReturning(Object retVal) {
        System.out.println("doBusinessActionAfterReturning = " + uniqueKey.get());
    }

    /**
     * After throwing advice runs when a matched method execution exits by throwing an exception
     */
    @AfterThrowing("serviceAction()")
    public void doBusinessActionAfterThrowing() {
        System.out.println("doBusinessActionAfterThrowing = " + uniqueKey.get());
    }
}
